﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CreateField.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The create field.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Scripting
{
    using System;
    using DataAccess;

    /// <summary>
    /// The create field.
    /// </summary>
    internal class CreateField : CreateBase
    {
        /// <summary>
        /// Gets sqlScript.
        /// </summary>
        public CreateTable SqlScript
        {
            get
            {
                return this.currentScript;
            }
        }

        /// <summary>
        /// The current script.
        /// </summary>
        private CreateTable currentScript = new CreateTable();

        /// <summary>
        /// The IndexRow.
        /// </summary>
        private DbObjectsDs.FieldsRow ir;

        /// <summary>
        /// Initializes a new instance of the <see cref="CreateField"/> class.
        /// </summary>
        /// <param name="schema">
        /// The schema.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="dtObjects">
        /// The dt objects.
        /// </param>
        /// <param name="scrOption">
        /// The scr option.
        /// </param>
        /// <param name="sqlVersion">
        /// The sql version.
        /// </param>
        public CreateField(string schema, string tableName, DatabaseDataSets dtObjects, SqlScriptingOption scrOption) : base(schema, tableName, string.Empty, dtObjects, scrOption)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CreateField"/> class.
        /// </summary>
        /// <param name="schema">
        /// The schema.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="columnName">
        /// The column name.
        /// </param>
        /// <param name="dtObjects">
        /// The dt objects.
        /// </param>
        /// <param name="scrOption">
        /// The scr option.
        /// </param>
        /// <param name="sqlVersion">
        /// The sql version.
        /// </param>
        public CreateField(string schema, string tableName, string columnName, DatabaseDataSets dtObjects, SqlScriptingOption scrOption) : base(schema, tableName, columnName, dtObjects, scrOption)
        {
        }

        /// <summary>
        /// The set rows.
        /// </summary>
        protected override void SetRows()
        {
            this.DataRowViews = this.DatabaseDiffData.GetField(this.Schema, this.TableName, this.Name);
        }

        /// <summary>
        /// The set current row.
        /// </summary>
        protected override void SetCurrentRow()
        {
            this.ir = (DatabaseDataSets.FieldsRow) this.DataRowViews[this.CurrentRow].Row ;
        }

        /// <summary>
        /// The row script.
        /// </summary>
        protected override void RowScript()
        {
            this.currentScript.field.AddElement(this.FieldNameFormat(this.ir), true, true);
                
            if (!this.ir.IsComputed)
            {
                this.currentScript.field.AddElement(this.FieldDataTypeFormat(this.ir), false, false);
                this.currentScript.field.AddElement(this.FieldIdentityFormat(this.ir), false, false);
                this.currentScript.field.AddElement(this.FieldNullFormat(this.ir), false, false);
                    
                this.FieldDefaultFormat(this.ir, ref this.currentScript);
                this.FieldRule(this.ir, ref this.currentScript);

            }
            else
            {
                this.currentScript.field.AddElement(this.FieldComputedFormat(this.ir), true, true);
            }

            this.currentScript.field.AddRowWithComma();
        }

        /// <summary>
        /// The make string.
        /// </summary>
        public void MakeString()
        {
            base.ToString();
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <returns>
        /// The to string.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public override string ToString()
        {
            throw new Exception("You can't use ToString()");
        }

        #region field script creation

        /// <summary>
        /// Computed field declaration
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field computed format.
        /// </returns>
        private string FieldComputedFormat(DbObjectsDs.FieldsRow f)
        {
            return f.IsComputed ? string.Format(" As {0} ", f.ComputedText) : string.Empty;
        }

        /// <summary>
        /// [name] [varchar] (60) 
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field data type format.
        /// </returns>
        private string FieldDataTypeFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;

            s = string.Format("{0}", QuoteName(f.DataTypeName));
            s += this.FieldRowGuiIDFormat(f);
            s += this.FieldLengthFormat(f);
            s += this.FieldCollateFormat(f);
            s += this.FieldPrecisionScaleFormat(f);

            return s;
        }

        /// <summary>
        /// The field row gui id format.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// The field row gui id format.
        /// </returns>
        private string FieldRowGuiIDFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;
            if (f.IsRowGuidCol)
            {
                s = " ROWGUIDCOL";
            }

            // ROWGUIDCOL
            if (s.Length != 0)
            {
                s += Space;
            }

            return s;
        }

        /// <summary>
        /// IDENTITY(1,1)
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field identity format.
        /// </returns>
        private string FieldIdentityFormat(DbObjectsDs.FieldsRow f)
        {
            string s = f.IsIdentity ?
                                        (string.Format("IDENTITY({0},{1})", f.IdentSeed, f.IdentIncr)
                                         + (f.IsIdNotForRepl ?
                                                                 cmdNotForReplication : string.Empty))
                           : string.Empty;
            if (s.Length != 0)
            {
                s += Space;
            }

            return s;
        }

        /// <summary>
        /// The field rule.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <param name="currentScript">
        /// The current script.
        /// </param>
        private void FieldRule(DbObjectsDs.FieldsRow f, ref CreateTable currentScript)
        {
            if (!f.IsRuleNameNull())
            {
                currentScript.afterCreateForBind.AddCommandTerminator(
                    this.spBindRule(f.RuleSchema, f.RuleName, f.SchemaName, f.TableName, f.Name));
            }

        }

        /// <summary>
        /// sp_bindrule
        /// </summary>
        /// <param name="RuleSchema">
        /// </param>
        /// <param name="RuleName">
        /// </param>
        /// <param name="TableSchema">
        /// </param>
        /// <param name="TableName">
        /// </param>
        /// <param name="FieldName">
        /// </param>
        /// <returns>
        /// The sp bind rule.
        /// </returns>
        public string spBindRule(string RuleSchema, string RuleName, string TableSchema, string TableName, string FieldName)
        {
            return string.Format("exec sp_bindrule @rulename='{0}.{1}',@objname='{2}.{3}.{4}'", QuoteName(RuleSchema), QuoteName(RuleName), QuoteName(TableSchema), QuoteName(TableName), QuoteName(FieldName));
        }

        /// <summary>
        /// sp_unbindrule
        /// </summary>
        /// <param name="TableSchema">
        /// </param>
        /// <param name="TableName">
        /// </param>
        /// <param name="FieldName">
        /// </param>
        /// <returns>
        /// The sp unbind rule.
        /// </returns>
        public string spUnbindRule(string TableSchema, string TableName, string FieldName)
        {
            return string.Format("exec sp_unbindrule @objname='{0}.{1}.{2}'", QuoteName(TableSchema), QuoteName(TableName), QuoteName(FieldName));
        }
        

        /// <summary>
        /// CONSTRAINT [DF__c__a__5837D2CA] DEFAULT (0)
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <param name="currentScript">
        /// The current Script.
        /// </param>
        private void FieldDefaultFormat(DbObjectsDs.FieldsRow f, ref CreateTable currentScript)
        {
            

            if (!f.IsConstrNameNull())
            {
                var row = this.DatabaseDiffData.DefaultCnst.FindBySchemaNameName(f.ConstrSchema, f.ConstrName);
                if (row != null)
                {
                    // ha ugyanaz a tulajdonosa a defaultnak, mint a táblának
                    if (row.SchemaName == f.SchemaName)
                    {
                        currentScript.field.AddElement(
                            f.ConstrNameIsGenerated
                                ? string.Format("DEFAULT {0}", row.Definition)
                                : string.Format("CONSTRAINT {0} DEFAULT {1}", f.ConstrName, row.Definition), false, true);
                    }
                    else
                    {
                        currentScript.afterCreateForBind.AddCommandTerminator(this.spBindDefault(f.SchemaName, f.TableName, f.ConstrSchema, f.ConstrName, f.Name));
                    }
                }
            }
            else if (!f.IsDefConstrNameNull())
            {
                currentScript.afterCreateForBind.AddCommandTerminator(this.spBindDefault(f.SchemaName, f.TableName, f.DefConstrSchema, f.DefConstrName, f.Name));
            }
        }
        

        /// <summary>
        /// Default binding to field
        /// </summary>
        /// <param name="tableSchema">
        /// </param>
        /// <param name="tableName">
        /// </param>
        /// <param name="defaultSchema">
        /// </param>
        /// <param name="defaultName">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The sp bind default.
        /// </returns>
        public string spBindDefault(string tableSchema, string tableName, string defaultSchema, string defaultName, string fieldName)
        {
            return string.Format("exec sp_bindefault @defname='{0}.{1}',@objname ='{2}.{3}.{4}'", QuoteName(defaultSchema), QuoteName(defaultName), QuoteName(tableSchema), QuoteName(tableName), QuoteName(fieldName));

        }

        /// <summary>
        /// Default unbinding from a field
        /// </summary>
        /// <param name="tableSchema">
        /// </param>
        /// <param name="tableName">
        /// </param>
        /// <param name="fieldName">
        /// </param>
        /// <returns>
        /// The sp unbind default.
        /// </returns>
        public string spUnbindDefault(string tableSchema, string tableName, string fieldName)
        {
            return string.Format("exec sp_unbindefault '{0}.{1}.{2}", QuoteName(tableSchema), QuoteName(tableName), QuoteName(fieldName));
        }

        /// <summary>
        /// NOT NULL or NULL
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field null format.
        /// </returns>
        private string FieldNullFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;
            s = f.AllowsNull ? "NULL" : "NOT NULL";

            if (s.Length != 0)
            {
                s += Space;
            }

            return s;
        }

        /// <summary>
        /// COLLATE SQL_Hungarian_CP1250_CI_AS NOT
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field collate format.
        /// </returns>
        private string FieldCollateFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;

            // this._SqlObjectOptions.GetCompareOptionBoolValue(OptionNames.isCompareCollation) 
            if (f.BaseTypeName != SysName && (!(f.IsCollationNull() || f.Collation.Trim().Length == 0) ))
            {
                s = string.Format("COLLATE {0} ", f.Collation);
            }

            return s;
        }

        /// <summary>
        /// (5, 0)
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field precision scale format.
        /// </returns>
        private string FieldPrecisionScaleFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;
            if ((f.BaseTypeName.IndexOf("decimal") != -1 || f.BaseTypeName.IndexOf("numeric") != -1) && f.BaseTypeName == f.DataTypeName)
            {
                s = string.Format(
                    "({0}{1})", f.Precision.ToString(), f.IsScaleNull() ? string.Empty : ("," + f.Scale.ToString()));
            }

            if (s.Length != 0)
            {
                s += Space;
            }
            return s;
        }

        /// <summary>
        /// Lenght Format (100)
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field length format.
        /// </returns>
        private string FieldLengthFormat(DbObjectsDs.FieldsRow f)
        {
            string s = string.Empty;
                
            if ((f.BaseTypeName.IndexOf("char") != -1
                 || f.BaseTypeName.IndexOf("binary") != -1)
                && f.BaseTypeName == f.DataTypeName
                )
                s = string.Format(" ({0})", f.Length==0 ? cmdVarcharMax : f.Length.ToString());
                

            s += Space;
            return s;
        }

        /// <summary>
        /// The field name format.
        /// </summary>
        /// <param name="f">
        /// </param>
        /// <returns>
        /// The field name format.
        /// </returns>
        private string FieldNameFormat(DbObjectsDs.FieldsRow f)
        {
            return QuoteName(f.Name);
        }

        #endregion field script creation		

    }
}